package GMDPRE

// JacP2AffC 将蒙哥马利域中的雅克比坐标点转为正常的仿射坐标点x和y
// 6次模乘，2次模幂(求逆)
func JacP2AffC(x *BN, y *BN, jp *JacPoint) {
	var tmp1, tmp2 BN

	if BnIsZero(&(jp.z), Sm2CurveDigit) == 1 {
		*x = Bn0
		*y = Bn0
		return
	}

	/* x = x / (z^2) */
	BnMontMul(&tmp1, &(jp.z), &(jp.z), &Sm2Q, Sm2McQ, Sm2CurveDigit)
	/* Improved mod_inverse: x^(-1) = x^(p-2)%p (Fermat's little theorem)*/
	BnMontExp(&tmp2, &tmp1, &Sm2QSub2, &Sm2Q, Sm2McQ, Sm2CurveDigit)
	BnMontMul(x, &(jp.x), &tmp2, &Sm2Q, Sm2McQ, Sm2CurveDigit)
	BnMontRdc(x, x, &Sm2Q, Sm2McQ, Sm2CurveDigit)
	/* y = y / (z^3) */
	BnMontMul(&tmp1, &tmp1, &(jp.z), &Sm2Q, Sm2McQ, Sm2CurveDigit)
	BnMontExp(&tmp2, &tmp1, &Sm2QSub2, &Sm2Q, Sm2McQ, Sm2CurveDigit)
	BnMontMul(y, &(jp.y), &tmp2, &Sm2Q, Sm2McQ, Sm2CurveDigit)
	BnMontRdc(y, y, &Sm2Q, Sm2McQ, Sm2CurveDigit)
}

// AffC2JacP 将正常的仿射坐标x和y转为蒙哥马利域中的雅克比坐标点
// 2次模乘
func AffC2JacP(jp *JacPoint, x *BN, y *BN) {
	BnMontMul(&(jp.x), x, &Sm2RRQ, &Sm2Q, Sm2McQ, Sm2CurveDigit)
	BnMontMul(&(jp.y), y, &Sm2RRQ, &Sm2Q, Sm2McQ, Sm2CurveDigit)
	jp.z = Sm2Mont1Q
}

// AffP2JacP 将正常的仿射坐标点转为蒙哥马利域中的雅克比坐标点
func AffP2JacP(jp *JacPoint, p *AffPoint) {
	BnMontMul(&jp.x, &p.x, &Sm2RRQ, &Sm2Q, Sm2McQ, Sm2CurveDigit)
	BnMontMul(&jp.y, &p.y, &Sm2RRQ, &Sm2Q, Sm2McQ, Sm2CurveDigit)
	jp.z = Sm2Mont1Q
}

func AffP2Bytes(p *AffPoint) []uint8 {
	res := BnToBytes(&(p.x), Sm2CurveDigit)
	res = append(res, BnToBytes(&(p.y), Sm2CurveDigit)...)
	return res
}

func Bytes2AffP(p *AffPoint, bytes []uint8) int {
	if len(bytes) != Sm2AffPointSize {
		return -1
	}
	BytesToBn(&p.x, Sm2CurveDigit, bytes[:Sm2CurveSize], Sm2CurveSize)
	BytesToBn(&p.y, Sm2CurveDigit, bytes[Sm2CurveSize:], Sm2CurveSize)
	return 0
}

func AffPEqual(ap1 *AffPoint, ap2 *AffPoint, digs int) bool {
	return BnCmp(&ap1.x, &ap2.x, digs) == 0 && BnCmp(&ap1.y, &ap2.y, digs) == 0
}

// GenBnLessN 生成小于N的数，N是Sm2中的参数
func GenBnLessN(bn *BN) {
	for {
		BytesToBn(bn, Sm2CurveDigit, GetRandomBytes(Sm2CurveSize), Sm2CurveSize)
		if BnCmp(bn, &(Sm2N), Sm2CurveDigit) == -1 {
			break
		}
	}
}
